package com.qomosoft.mediacodectest;

import android.Manifest;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
import android.hardware.Camera;
import android.media.MediaCodec;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import com.ont.rtmpclient.rtmp.RtmpPublisher;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback {
    private static final String TAG = MainActivity.class.getSimpleName();

    public static final int NAL_SLICE = 1;
    public static final int NAL_SLICE_DPA = 2;
    public static final int NAL_SLICE_DPB = 3;
    public static final int NAL_SLICE_DPC = 4;
    public static final int NAL_SLICE_IDR = 5;
    public static final int NAL_SEI = 6;
    public static final int NAL_SPS = 7;
    public static final int NAL_PPS = 8;
    public static final int NAL_AUD = 9;
    public static final int NAL_FILLER = 12;

    private SurfaceView mSurfaceView;
    private SurfaceHolder mSurfaceHolder;
    private Camera mCamera;
    private OutputStream outputStream;
    private QMAVCEncoder mAVCEncoder;
    public static final int PREVIEW_WIDTH = 640;
    public static final int PREVIEW_HEIGHT = 480;
    public static final int PREVIEW_FRAMERATE = 30;
    private RtmpPublisher mRtmpPublisher;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
//        requestPermission();
        needRequestPermission();
        initViews();
        try {
            outputStream = new FileOutputStream("/sdcard/abc.h264");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        mRtmpPublisher = RtmpPublisher.newInstance();
        int ret = mRtmpPublisher.init("rtmp://172.29.31.140:1935/rtmplive/home", PREVIEW_WIDTH, PREVIEW_HEIGHT, 30000);
        if (ret < 0) {
            Log.e(TAG, ">>>>> RTMP init failed! <<<<<<");
        }
        mAVCEncoder = new QMAVCEncoder(PREVIEW_WIDTH, PREVIEW_HEIGHT, PREVIEW_FRAMERATE, new QMAVCEncoder.QMAVCEncoderCallback() {
            @Override
            public void onDataEncode(ByteBuffer buffer, MediaCodec.BufferInfo bufferInfo) {
                onEncodedAvcFrame(buffer, bufferInfo);
//                try {
//                    byte[] outData = new byte[bufferInfo.size];
//                    buffer.get(outData);
//                    outputStream.write(outData);
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
            }
        });
    }

    private void initViews() {
        mSurfaceView = findViewById(R.id.sv_preview);
        mSurfaceHolder = mSurfaceView.getHolder();
        mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        mSurfaceHolder.addCallback(this);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        openCamera(holder);
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        closeCamera();
    }

    private void requestPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            requestPermissions(new String[] {Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.INTERNET}, 0);
        }
    }

    private void openCamera(SurfaceHolder holder) {
        mCamera = Camera.open();
        mCamera.setDisplayOrientation(90);
        Camera.Parameters parameters = mCamera.getParameters();
        parameters.setPreviewFormat(ImageFormat.NV21);
        parameters.setPreviewSize(PREVIEW_WIDTH, PREVIEW_HEIGHT);
        parameters.setPreviewFrameRate(PREVIEW_FRAMERATE);
        List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();
        List<Integer> formats = parameters.getSupportedPreviewFormats();
        Log.e(TAG, "==================================");
        Log.e(TAG, "Supported preview size:");
        for (Camera.Size size : previewSizes) {
            Log.e(TAG, String.format("[%d x %d]", size.width, size.height));
        }
        Log.e(TAG, "Supported preview format:");
        for (Integer i : formats) {
            Log.e(TAG, Integer.toHexString(i));
        }
        Log.e(TAG, "==================================");
        mCamera.setParameters(parameters);
        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
            mCamera.setPreviewCallback(new Camera.PreviewCallback() {
                @Override
                public void onPreviewFrame(byte[] data, Camera camera) {
                    // TODO(decode and encode)
                    mAVCEncoder.encode(data);
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void closeCamera() {
        if (outputStream != null) {
            try {
                mRtmpPublisher.stop();
                mAVCEncoder.release();
                outputStream.flush();
                outputStream.close();
                outputStream = null;
                mAVCEncoder = null;
                mRtmpPublisher = null;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (mCamera != null) {
            mCamera.stopPreview();
            mCamera.setPreviewCallback(null);
            mCamera.release();
            mCamera = null;
        }
    }

    private void onEncodedAvcFrame(ByteBuffer bb, final MediaCodec.BufferInfo vBufferInfo) {
        int offset = 4;
        //判断帧的类型
        if (bb.get(2) == 0x01) {
            offset = 3;
        }
        int type = bb.get(offset) & 0x1f;
        Log.d(TAG, "type=" + type);
        if (type == NAL_SPS) {
            //[0, 0, 0, 1, 103, 66, -64, 13, -38, 5, -126, 90, 1, -31, 16, -115, 64, 0, 0, 0, 1, 104, -50, 6, -30]
            //打印发现这里将 SPS帧和 PPS帧合在了一起发送
            // SPS为 [4，len-8]
            // PPS为后4个字节
            final byte[] pps = new byte[4];
            final byte[] sps = new byte[vBufferInfo.size - 12];
            bb.getInt();// 抛弃 0,0,0,1
            bb.get(sps, 0, sps.length);
            bb.getInt();
            bb.get(pps, 0, pps.length);
            Log.e(TAG, "解析得到 sps:" + Arrays.toString(sps) + ",PPS=" + Arrays.toString(pps));
            mRtmpPublisher.sendSpsAndPps(sps, sps.length, pps, pps.length,
                    vBufferInfo.presentationTimeUs / 1000);
//            Runnable runnable = new Runnable() {
//                @Override
//                public void run() {
//                    mRtmpPublisher.sendSpsAndPps(sps, sps.length, pps, pps.length,
//                            vBufferInfo.presentationTimeUs / 1000);
//                }
//            };
//            try {
//                mRunnables.put(runnable);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }

        } else if (type == NAL_SLICE || type == NAL_SLICE_IDR) {
            final byte[] bytes = new byte[vBufferInfo.size];
            bb.get(bytes);
            mRtmpPublisher.sendVideoData(bytes, bytes.length,
                    vBufferInfo.presentationTimeUs / 1000);
//            Runnable runnable = new Runnable() {
//                @Override
//                public void run() {
//                    mRtmpPublisher.sendVideoData(bytes, bytes.length,
//                            vBufferInfo.presentationTimeUs / 1000);
//                }
//            };
//            try {
//                mRunnables.put(runnable);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }

        }

    }

    private boolean needRequestPermission() {
        //Camera 权限提前判断！！！
        if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            List<String> permissions = new ArrayList<>();
            int resultAudio = ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO);
            int resultCamera = ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA);
            if (resultAudio != PackageManager.PERMISSION_GRANTED) {
                permissions.add(Manifest.permission.RECORD_AUDIO);
            }
            if (resultCamera != PackageManager.PERMISSION_GRANTED) {
                permissions.add(Manifest.permission.CAMERA);
            }
            if (permissions.size() > 0) {
                ActivityCompat.requestPermissions(this, permissions.toArray(new String[permissions.size()]), 1);
                return true;
            }

        }
        return false;
    }
}
